// 定义接口需要用关键词interface 
// 在java里 定义接口类名 一般会用 ILabelledValue 
// 变量命名的原则: 从命名上能够清除的明确数据类型和作用 nameArr
// 对象类型的接口描述
interface ILabelledValue {
  label: string;
}
// 声明了函数 传参类型必须约束 要不然在调用的时候可能传递任意类型
function printLabel(labelledObj: ILabelledValue) {
  console.log(labelledObj.label);
}
// 字面量对象 有label 鸭子类型就认为是符合接口形式的
// 注意,多了一个size属性,但并没有触发ts的类型错误提示
const myObj = {size: 10, label: "Size 10 Object"};
printLabel(myObj);
console.log('=========');
// 如果一个接口某些属性是可选的,可以用?声明
// ts如果声明某个属性是可选的,ts默认是undefined类型
interface SquareConfig {
  color?: string;
  width?: number;
}
// 定义函数 形参config是SquareConfig类型,参数color和width可传可不传
// 函数声明: 返回值({color: string; area: number})
function createSquare(config: SquareConfig): {color: string; area: number} {
  const newSquare = {color: "white", area: 100};
  if (config.color) {
    newSquare.color = config.color;
  }
  if (config.width) {
    newSquare.area = config.width * config.width;
  }
  return newSquare;
}
// 虽然额外的属性并不会影响结果,但是ts还是提示错误了,帮助我们在开发阶段就发现问题
// ts中最好对每一个对象都声明类型,避免绕过ts类型检测导致代码bug
const configParams: SquareConfig = {color:'white',width: 100};
const mySquare = createSquare(configParams);
// 采用断言 强制声明类型 断言前提: “相信我，我知道自己在干什么”
// 可用吗? 可以. 但是只是绕过ts的类型检查,不代表以后不会出现bug.
const mySquare2 = createSquare({ width: 100, opacity: 0.5 } as SquareConfig);
console.log(mySquare,mySquare2);

// 函数的类型 对函数的类型声明
interface ISearchFunc {
  (source: string, subString: string): boolean;
}
const mySearch: ISearchFunc = function(source: string, subString: string) {
  const result = source.search(subString);
  return result > -1;
}
console.log(mySearch('a','b'));
// 类类型  用类实现接口
interface ClockInterface {
  currentTime: Date;
  setTime: (d: Date) => any;
}
// class  extends 
// implements(实现) 用于类实现接口(的方法)
// extends(继承) 用于类合并父类的属性和方法
class Clock implements ClockInterface {
  currentTime=new Date();
  h: number;
  m: number;
  setTime(d: Date) {
      this.currentTime = d;
      console.log(this.h,this.m);
  }
  constructor(h: number, m: number) {
    this.h = h;
    this.m = m;
   }
}

const nowTime = new Clock(1,2);
nowTime.setTime(new Date());

// 继承接口 extends可以显示的合并接口
interface Shape {
  color: string;
}
// Square对shape进行了属性合并
interface Square extends Shape {
  sideLength: number;
}

const square: Square  = {
  color: 'green',
  sideLength: 10
}
console.log(square);
// 多继承
interface Shape {
  color: string;
}

interface PenStroke {
  penWidth: number;
}
// java中式多实现(implement) 单继承 (extend),这里有区别
interface Square extends Shape, PenStroke {
  sideLength: number;
}

const square2: Square = {
  color: 'green',
  sideLength: 10,
  penWidth: 5.0
}
console.log(square2);
// 总结: 接口作用是 "契约"
// 可以约束  对象类型, 函数, 类 , 可以被接口继承 ,可以多继承.
// 到此可以对基本数据类型和任意其他类型进行类型声明(约束)
